home *** CD-ROM | disk | FTP | other *** search
- /* Read, sort and compare two directories. Used for GNU DIFF.
- Copyright (C) 1988 Free Software Foundation, Inc.
-
- This file is part of GNU DIFF.
-
- GNU DIFF is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY. No author or distributor
- accepts responsibility to anyone for the consequences of using it
- or for whether it serves any particular purpose or works at all,
- unless he says so in writing. Refer to the GNU DIFF General Public
- License for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- GNU DIFF, but only under the conditions described in the
- GNU DIFF General Public License. A copy of this license is
- supposed to have been given to you along with GNU DIFF so you
- can know your rights and responsibilities. It should be in a
- file named COPYING. Among other things, the copyright notice
- and this notice must be preserved on all copies. */
-
- #include "diff.h"
-
- static int compare_names ();
-
- /* Read the directory named DIRNAME and return a sorted vector
- of filenames for its contents. */
-
- struct dirdata
- {
- int length; /* # elements in `files' */
- char **files; /* Sorted names of files in the dir */
- };
-
- #if defined(MSDOS)
- /*
- ** due to difference of opinion btw gnu and microsoft about what
- ** const means, const is defined away in diff.h, which causes warnings
- ** when compiling the headers. This ugliness is avoided here.
- */
- #ifdef const
- #undef const
- #endif
- #include <string.h>
- #include <dos.h>
-
- struct direct {
- char d_name[14];
- };
-
- typedef struct _dir {
- int first;
- struct find_t dta;
- struct direct current;
- } DIR;
-
-
- DIR *
- opendir(char *name) {
- char localname[65];
- DIR *rval = malloc(sizeof(DIR));
- strcpy(localname,name);
- strcat(localname,"\\*.*");
- if(rval == NULL ||
- _dos_findfirst(localname,_A_NORMAL|_A_SUBDIR,&rval->dta) != 0)
- return NULL;
- rval->first = 1;
- return rval;
- }
-
- void
- closedir(DIR *x) {
- free(x);
- }
-
- struct direct *
- readdir(DIR *thisdir) {
- /*
- ** first time through, we don't need to look for a file
- */
- if(!thisdir->first) {
- if(_dos_findnext(&thisdir->dta) != 0)
- return NULL;
- } else
- thisdir->first = 0;
- strncpy(thisdir->current.d_name,thisdir->dta.name,13);
- thisdir->current.d_name[13] = '\0';
- strlwr(thisdir->current.d_name);
- return &thisdir->current;
- }
-
- #endif /* MSDOS */
-
- static struct dirdata
- dir_sort (dirname)
- char *dirname;
- {
- register DIR *reading;
- register struct direct *next;
- struct dirdata dirdata;
- int compare_names ();
-
- /* Address of block containing the files that are described. */
- char **files;
-
- /* Length of block that `files' points to, measured in files. */
- int nfiles;
-
- /* Index of first unused in `files'. */
- int files_index;
-
- /* Open the directory and check for errors. */
- reading = opendir (dirname);
- if (!reading)
- {
- pfatal_with_name (dirname);
- return dirdata;
- }
-
- /* Initialize the table of filenames. */
-
- nfiles = 100;
- files = (char **) xmalloc (nfiles * sizeof (char *));
- files_index = 0;
-
- /* Read the directory entries, and insert the subfiles
- into the `files' table. */
-
- while (next = readdir (reading))
- {
- /* Ignore the files `.' and `..' */
- if (next->d_name[0] == '.'
- && (next->d_name[1] == 0
- || (next->d_name[1] == '.'
- && next->d_name[2] == 0)))
- continue;
-
- if (files_index == nfiles)
- {
- nfiles *= 2;
- files
- = (char **) xrealloc (files, sizeof (char *) * nfiles);
- }
- files[files_index++] = concat (next->d_name, "", "");
- }
-
- closedir (reading);
-
- /* Sort the table. */
- qsort (files, files_index, sizeof (char *), compare_names);
-
- /* Return a description of location and length of the table. */
- dirdata.files = files;
- dirdata.length = files_index;
-
- return dirdata;
- }
-
- /* Sort the files now in the table. */
-
- static int
- compare_names (file1, file2)
- char **file1, **file2;
- {
- return strcmp (*file1, *file2);
- }
-
- /* Compare the contents of two directories named NAME1 and NAME2.
- This is a top-level routine; it does everything necessary for diff
- on two directories.
-
- HANDLE_FILE is a caller-provided subroutine called to handle each file.
- It gets five operands: dir and name (rel to original working dir) of file
- in dir 1, dir and name pathname of file in dir 2, and the recursion depth.
-
- For a file that appears in only one of the dirs, one of the name-args
- to HANDLE_FILE is zero.
-
- DEPTH is the current depth in recursion.
-
- Returns the maximum of all the values returned by HANDLE_FILE. */
-
- int
- diff_dirs (name1, name2, handle_file, depth)
- char *name1, *name2;
- #if !defined(MSDOS)
- int (*handle_file) ();
- #else
- /* sorry, rms, I can't live with the assumption that
- ** sizeof(char *) == sizeof(int)
- */
- int (*handle_file)(char *dir0,char *name0,
- char *dir1,char *name1,int depth);
- #endif
- {
- struct dirdata data1, data2;
- register int i1, i2;
- int val = 0;
- int v1;
-
- /* Get sorted contents of both dirs. */
- data1 = dir_sort (name1);
- data2 = dir_sort (name2);
-
- i1 = 0;
- i2 = 0;
-
- /* If -Sname was specified, and this is the topmost level of comparison,
- ignore all file names less than the specified starting name. */
-
- if (dir_start_file && depth == 0)
- {
- while (i1 < data1.length && strcmp (data1.files[i1], dir_start_file) < 0)
- i1++;
- while (i2 < data2.length && strcmp (data2.files[i2], dir_start_file) < 0)
- i2++;
- }
-
- /* Loop while files remain in one or both dirs. */
- while (i1 < data1.length || i2 < data2.length)
- {
- int nameorder;
-
- /* Compare next name in dir 1 with next name in dir 2.
- At the end of a dir,
- pretend the "next name" in that dir is very large. */
-
- if (i1 == data1.length)
- nameorder = 1;
- else if (i2 == data2.length)
- nameorder = -1;
- else
- nameorder = strcmp (data1.files[i1], data2.files[i2]);
-
- if (nameorder == 0)
- {
- /* We have found a file (or subdir) in common between both dirs.
- Compare the two files. */
- v1 = handle_file (name1, data1.files[i1], name2, data2.files[i2],
- depth + 1);
- i1++, i2++;
- }
- if (nameorder < 0)
- {
- /* Next filename in dir 1 is less; that is a file in dir 1 only. */
- v1 = handle_file (name1, data1.files[i1], name2, (char *)0,
- depth + 1);
- i1++;
- }
- if (nameorder > 0)
- {
- /* Next filename in dir 2 is less; that is a file in dir 2 only. */
- v1 = handle_file (name1, (char *)0, name2, data2.files[i2],
- depth + 1);
- i2++;
- }
- if (v1 > val)
- val = v1;
- }
- free (data1.files);
- free (data2.files);
-
- return val;
- }
-